home *** CD-ROM | disk | FTP | other *** search
/ MACD 5 / MACD 5.bin / workbench / tools / czesc_1 / dr / source / smallio.c < prev   
C/C++ Source or Header  |  1993-11-21  |  9KB  |  415 lines

  1. /*  SMALLIO.C  */
  2.  
  3. #ifdef THIS_IS_A_COMMENT
  4.  
  5. This is a stripped-down of my old PUREIO.C which I used to use for Dr ... but
  6. Dr now uses my PURIFY.A startup code for purity, so now this is just a sort of
  7. miniature stdio, with optional asynchronous background output if BACKGROUND is
  8. defined.
  9.  
  10. The functions offered are all void except OpenSmallIO, which returns nonzero if
  11. there's insufficient memory.  You can declare it as either short or long.  They
  12. are named differently from the nearest equivalent stdio functions.  You can
  13. #define the usual names to be these if you want, but don't use those in places
  14. where you expect a return value.  The functions are:
  15.  
  16.     BOOL OpenSmallIO(void (*ffunc)(void))    /* call before anything else */
  17.     void puch(ushort c)        /* like putchar(), writes one character      */
  18.     void put(char *s)        /* like fputs(s, stdout), writes the string  */
  19.     void putfmt(char *fmt, ...)    /* a simple printf, based on RawDoFmt        */
  20.     void pflush(void)        /* flushes buffered output                   */
  21.     void CloseSmallIO(void)    /* releases memory, etc; call this last      */
  22.  
  23.     void StopAllOutput(void)    /* what it says ... BACKGROUND version only  */
  24.  
  25. We make the argument to puch a short rather than a char just to save trouble.
  26. The argument to OpenSmallIO is a function to be called to check for a control-C
  27. break and handle it if present.  NULL is okay.
  28.  
  29. #endif THIS_IS_A_COMMENT
  30.  
  31.  
  32. #include <exec/ports.h>
  33. #include <exec/memory.h>
  34. #include <dos/dosextens.h>
  35. #include <dos/dostags.h>
  36. #include <Paul.h>
  37.  
  38. #ifdef put
  39. #  undef put
  40. #endif
  41.  
  42.  
  43. #define BUFSIZE 300
  44. char _smallIO_buffer[BUFSIZE];
  45. short _smallIO_bufpos;
  46.  
  47. private BPTR koss;        /* our output filehandle */
  48.  
  49. private void (*CC)(void);
  50.  
  51. #ifdef BACKGROUND
  52.  
  53. #  define BBSIZE 8000
  54.  
  55. private str bigbuffer;
  56. private volatile short bbegin, bbend;        /* equal when buffer empty */
  57. private volatile bool pumping = false, dumping = false;
  58.  
  59. private struct Process *meee, *pumpproc;
  60. private struct MsgPort *momport;
  61. private short momportsig;
  62.  
  63. extern struct Library *DOSBase;
  64.  
  65.  
  66.  
  67. #asm
  68.         public    ___readA4msg
  69.  
  70. FindTask    equ    -294
  71. WaitPort    equ    -384
  72. GetMsg        equ    -372
  73. pr_MsgPort    equ    92
  74. ln_Name        equ    10
  75.  
  76. ___readA4msg:    movem.l    a5/a6,-(sp)
  77.         move.l    (4).w,a6
  78.         sub.l    a1,a1
  79.         jsr    FindTask(a6)
  80.         move.l    d0,a5
  81.         lea    pr_MsgPort(a5),a0
  82.         jsr    WaitPort(a6)
  83.         lea    pr_MsgPort(a5),a0
  84.         jsr    GetMsg(a6)
  85.         move.l    d0,a4
  86.         move.l    ln_Name(a4),a4        ; get parent's A4 value
  87.         movem.l    (sp)+,a5/a6
  88.         rts                ; return the message gotten
  89. #endasm
  90.  
  91. struct Message *__readA4msg(void);
  92.  
  93.  
  94.  
  95. private void BackgroundPump(void)
  96. {
  97.     struct Message *mom;
  98.     struct Process *myself;
  99.     struct Task *parent;
  100.     long sigs;
  101.     ustr line;
  102.     short llen, newbeg;
  103.     struct Library *DOSBase;
  104.  
  105.     mom = __readA4msg();        /* we can use global vars now */
  106.     DOSBase = OpenL("dos");        /* play by the rules, eh */
  107.     parent = mom->mn_ReplyPort->mp_SigTask;
  108.     pumping = true;
  109.     Signal(parent, SIGBREAKF_CTRL_F);
  110.     for (;;) {
  111.     sigs = Wait(SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_F);
  112.     if (sigs & SIGBREAKF_CTRL_C) {
  113.         Signal(parent, SIGBREAKF_CTRL_C);    /* "quitting; you should too" */
  114.         break;
  115.     }
  116.     if (dumping)
  117.         break;
  118.     while (bbegin != bbend && !dumping) {    /* only reference to bbend */
  119.         line = bigbuffer + bbegin;
  120.         llen = strlen(line);
  121.         if (llen)
  122.         Write(koss, line, (long) llen);
  123.         newbeg = bbegin + llen + 1;
  124.         if (newbeg < BBSIZE)
  125.         bbegin = newbeg;
  126.         else
  127.         bbegin = 0;
  128.         Signal(parent, SIGBREAKF_CTRL_F);    /* "there's more room now" */
  129.         if (SetSignal(0, 0) & SIGBREAKF_CTRL_C)
  130.         break;
  131.     }
  132.     }
  133.     Forbid();
  134.     pumping = false;
  135.     bbegin = bbend;
  136.     pumpproc = null;
  137.     CloseLibrary(DOSBase);
  138.     ReplyMsg(mom);
  139. }
  140.  
  141.  
  142.  
  143. private void WaitForRoom(void)
  144. {
  145.     long sigs;
  146.  
  147.     Forbid();
  148.     if (pumpproc) {
  149.     sigs = Wait(SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_F | bit(momportsig));
  150. /* CAREFUL that removing momportsig here doesn't break something! */
  151.     if (pumpproc && sigs & SIGBREAKF_CTRL_C)
  152.         Signal((adr) pumpproc, SIGBREAKF_CTRL_C);    /* "let's both quit" */
  153.     }
  154.     Permit();
  155. }
  156.  
  157.  
  158.  
  159. private short Paste(short oldend, str what, short whatlen)
  160. {
  161.     short newend;
  162.  
  163.     if (whatlen)
  164.     strncpy(bigbuffer + oldend, what, (size_t) whatlen);
  165.     newend = oldend + whatlen;
  166.     bigbuffer[newend++] = '\0';
  167.     return newend;
  168. }
  169.  
  170.  
  171.  
  172. void _smallIO_flushline(void)
  173. {
  174.     short space, nowbegin, newend, chunk;
  175.  
  176.     if (!_smallIO_bufpos)
  177.     return;
  178.     if (!pumping) {
  179.     Write(koss, _smallIO_buffer, (long) _smallIO_bufpos);
  180.     _smallIO_bufpos = 0;
  181.     if (CC) CC();
  182.     return;
  183.     }
  184.     for (;;) {
  185.     nowbegin = bbegin;        /* snapshot */
  186.     if (bbend < nowbegin)
  187.         space = nowbegin - bbend - 1;
  188.     else
  189.         space = (nowbegin + BBSIZE - 2) - bbend;
  190.     if (space >= _smallIO_bufpos)
  191.         break;
  192.     WaitForRoom();
  193.     }
  194.     if (bbend < nowbegin || BBSIZE - bbend > _smallIO_bufpos)
  195.     newend = Paste(bbend, _smallIO_buffer, _smallIO_bufpos);
  196.     else {
  197.     chunk = BBSIZE - bbend - 1;        /* may be zero */
  198.     Paste(bbend, _smallIO_buffer, chunk);
  199.     newend = Paste(0, _smallIO_buffer + chunk, _smallIO_bufpos - chunk);
  200.     }
  201.     if (newend >= BBSIZE)
  202.     bbend = 0;
  203.     else
  204.     bbend = newend;
  205.     _smallIO_bufpos = 0;
  206.     meee->pr_Result2 = 0;
  207.     Signal((adr) pumpproc, SIGBREAKF_CTRL_F);    /* "get to woik, you" */
  208.     if (CC) CC();
  209. }
  210.  
  211.  
  212.  
  213. void pflush(void)
  214. {
  215.     if (!pumping)
  216.     return;
  217.     _smallIO_flushline();
  218.     while (bbend != bbegin)
  219.     WaitForRoom();
  220. }
  221.  
  222.  
  223.  
  224. void StopAllOutput(void)
  225. {
  226.     Forbid();
  227.     dumping = true;
  228.     if (pumpproc)
  229.     Signal((adr) pumpproc, SIGBREAKF_CTRL_F); /* "got a surprise for you" */
  230.     while (pumping)
  231.     WaitForRoom();
  232.     Permit();
  233. }
  234.  
  235. #else /* !BACKGROUND */
  236.  
  237. void pflush(void)
  238. {
  239.     if (_smallIO_bufpos)
  240.     Write(koss, _smallIO_buffer, (long) _smallIO_bufpos);
  241.     _smallIO_bufpos = 0;
  242.     if (CC) CC();
  243. }
  244.  
  245. #  define _smallIO_flushline pflush
  246.  
  247. #endif /* BACKGROUND */
  248.  
  249.  
  250.  
  251. #ifdef C_PUCH
  252.  
  253. void puch(ushort c)
  254. {
  255.     if (c == '\n')
  256.     while (_smallIO_bufpos && _smallIO_buffer[_smallIO_bufpos - 1] == ' ')
  257.         _smallIO_bufpos--;
  258.     _smallIO_buffer[_smallIO_bufpos++] = (char) c;
  259.     if (c == '\n' || _smallIO_bufpos >= BUFSIZE)
  260.     _smallIO_flushline();
  261. }
  262.  
  263. #else
  264.  
  265. void puch(ushort c);
  266. #  asm
  267.     public    _puch        ; profiling says this is worth optimizing...
  268.     cseg
  269.  
  270. c    equr    d0
  271. bpos    equr    d1
  272. buf    equr    a0
  273. BUFSIZE    equ    300        ; MAKE SURE THIS MATCHES the C definition!
  274.  
  275. _puch:    move.w    4(sp),c
  276.     move.w    __smallIO_bufpos,bpos
  277.     lea    __smallIO_buffer,buf
  278.     cmp.b    #10,c        ; newline?
  279.     bne.s    allies
  280. heil:    tst.w    bpos
  281.     beq.s    allies
  282.     cmp.b    #32,-1(buf,bpos.w)
  283.     bne.s    allies
  284.     dbra    bpos,heil    ; decrements and always branches back
  285. allies:    move.b    c,(buf,bpos.w)
  286.     addq.w    #1,bpos
  287.     move.w    bpos,__smallIO_bufpos
  288.     cmp.b    #10,c
  289.     beq.s    flshu
  290.     cmp.w    #BUFSIZE,bpos
  291.     blt.s    puxt
  292. flshu:    bsr    __smallIO_flushline
  293. puxt:    rts
  294.  
  295. #  endasm
  296. #endif
  297.  
  298.  
  299.  
  300. void put(register str s)
  301. {
  302.     while (*s)
  303.     puch(*(s++));
  304. }
  305.  
  306.  
  307.  
  308. #asm
  309.         public    ___moma4
  310. ___moma4:    move.l    a4,d0
  311.         rts
  312. #endasm
  313.  
  314. adr __moma4(void);
  315.  
  316.  
  317. private long tagz[] = {
  318.     NP_Entry, 0L, NP_Priority, 0L, NP_Name, 0L, NP_Input, NULL, NP_Output, NULL,
  319.     NP_Error, NULL, NP_StackSize, 2000L, NP_CopyVars, (long) FALSE, TAG_DONE
  320. };
  321.  
  322. long OpenSmallIO(void (*ffunc)(void))
  323. {
  324.     register struct Message *mom;
  325.     _smallIO_bufpos = 0;        /* set buffer to emptiness */
  326.     if (!(koss = Output()))
  327.     return 1;
  328.     CC = ffunc;
  329. #ifdef BACKGROUND
  330.     meee = ThisProcess();
  331.     if (bigbuffer = AllocP(BBSIZE)) {
  332.     bbegin = bbend = 0;
  333.     if (momport = CreateMsgPort()) {
  334.         if (NEWP(mom)) {
  335.         long mypri = meee->pr_Task.tc_Node.ln_Pri;
  336.         static ubyte name[] = "Dr output pump";
  337.  
  338.         mom->mn_Node.ln_Name = __moma4();
  339.         mom->mn_ReplyPort = momport;
  340.         momportsig = momport->mp_SigBit;
  341.         tagz[1] = (long) BackgroundPump;
  342.         tagz[3] = mypri;
  343.         tagz[5] = (long) &name[0];
  344.         if (pumpproc = CreateNewProc((adr) tagz)) {
  345.             PutMsg(&pumpproc->pr_MsgPort, mom);
  346.             while (!pumping && pumpproc)
  347.             Wait(SIGBREAKF_CTRL_F | bit(momportsig));
  348.         }
  349.         if (pumpproc) 
  350.             return 0;
  351.         FREE(mom);
  352.         }
  353.         DeleteMsgPort(momport);
  354.         momport = null;
  355.     }
  356.     FreeMem(bigbuffer, BBSIZE);
  357.     }
  358.     return 1;
  359. #else
  360.     return 0;
  361. #endif
  362. }
  363.  
  364.  
  365.  
  366. void CloseSmallIO(void)
  367. {
  368.     pflush();
  369. #ifdef BACKGROUND
  370.     if (momport) {
  371.     struct Message *mom;
  372.     StopAllOutput();
  373.     WaitPort(momport);    /* BackgroundPump is gone when msg received */
  374.     mom = GetMsg(momport);
  375.     FREE(mom);
  376.     DeleteMsgPort(momport);
  377.     }
  378.     if (bigbuffer)
  379.     FreeMem(bigbuffer, BBSIZE);
  380. #endif
  381. }
  382.  
  383.  
  384.  
  385. #asm
  386.     ; void putfmt(format, ...) str format; (whatever) items; ...
  387.  
  388.     public    _putfmt,_LVORawDoFmt,_geta4
  389.  
  390. put1:    ext.w    d0        ; necessary
  391.     beq.s    naw        ; RawDoFmt sends trailing nul
  392.     movem.l    d2/d3/a4/a6,-(sp)
  393.     FAR CODE
  394.     jsr    _geta4        ; won't hurt large data programs
  395.     NEAR CODE        ; won't hurt cause we're near end of source file
  396.     move.w    d0,-(sp)
  397.     bsr    _puch        ; this is a glue routine, see
  398.     addq    #2,sp
  399.     movem.l    (sp)+,d2/d3/a4/a6
  400. naw:    rts
  401.  
  402. RawDoFmt    equ    -522
  403.  
  404. _putfmt:
  405.     movem.l    a2-a6,-(sp)    ; play it safe
  406.     move.l    24(sp),a0    ; format
  407.     lea    28(sp),a1    ; data items
  408.     lea    put1,a2        ; putting func - no second parm, garbage in a3
  409.     move.l    4,a6
  410.     jsr    RawDoFmt(a6)
  411.     movem.l    (sp)+,a2-a6
  412.     rts
  413.  
  414. #endasm
  415.